package com.github.threefish.spring.sqltpl;

import com.github.threefish.spring.sqltpl.annotation.SqlXml;
import com.github.threefish.spring.sqltpl.exception.SqlTemplateXmlNotFoundException;
import com.github.threefish.spring.sqltpl.resource.FileResource;
import com.github.threefish.spring.sqltpl.resource.JarResource;
import com.github.threefish.spring.sqltpl.service.ISqlTemplteEngine;
import com.github.threefish.spring.sqltpl.service.ISqlTpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.Assert;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.Objects;

/**
 * @author 黄川 huchuc@vip.qq.com
 * date 2020/3/11
 */
public class SqlXmlBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {

    private static final Logger LOGGER = LoggerFactory.getLogger(SqlXmlBeanPostProcessor.class);
    private static final String JAR = "jar";
    private static final String XML = ".xml";
    private ApplicationContext applicationContext;
    private ISqlTemplteEngine iSqlTemplteEngine;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof ISqlTpl) {
            ISqlTpl iSqlTpl = (ISqlTpl) bean;
            Class klass = bean.getClass();
            SqlXml sqls = (SqlXml) klass.getAnnotation(SqlXml.class);
            if (sqls != null) {
                iSqlTpl.setSqlTpl(getSqlTplHolder(klass, getXmlName(klass), getiSqlTemplteEngine()));
            }
        }
        return bean;
    }

    /**
     * @return sql渲染器
     */
    private ISqlTemplteEngine getiSqlTemplteEngine() {
        if (Objects.isNull(iSqlTemplteEngine)) {
            iSqlTemplteEngine = applicationContext.getBean(ISqlTemplteEngine.class);
        }
        return iSqlTemplteEngine;
    }

    /**
     * @param klass
     * @return 取得xml文件名
     */
    private String getXmlName(Class klass) {
        SqlXml sqls = (SqlXml) klass.getAnnotation(SqlXml.class);
        return "".equals(sqls.value()) ? klass.getSimpleName().concat(XML) : sqls.value();
    }

    /**
     * @param klass
     * @param fileName
     * @return 取得xml文件
     */
    private SqlTplHolder getSqlTplHolder(Class klass, String fileName, ISqlTemplteEngine sqlTemplteEngine) {
        try {
            String xmlPath = klass.getPackage().getName().replace(".", File.separator) + File.separator + fileName;
            URL url = klass.getClassLoader().getResource(xmlPath);
            Assert.notNull(url, String.format("sqls xml [%s] is not exists!!!", xmlPath));
            if (JAR.equals(url.getProtocol())) {
                return new SqlTplHolder(
                        new SqlTplResourceLoader(new JarResource(new File(klass.getProtectionDomain().getCodeSource().getLocation().getPath()), url),
                                sqlTemplteEngine));
            } else {
                File file = new File(URLDecoder.decode(url.getFile(), Charset.defaultCharset().name()));
                if (file.exists()) {
                    return new SqlTplHolder(new SqlTplResourceLoader(new FileResource(file), sqlTemplteEngine));
                }
            }
            throw new SqlTemplateXmlNotFoundException(String.format("sqls xml [%s] is not exists!!!", xmlPath));
        } catch (UnsupportedEncodingException e) {
            LOGGER.error("不支持的编码异常", e);
            throw new SqlTemplateXmlNotFoundException(e);
        }
    }


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }


}
